#include <QFileDialog>
#include <QStandardPaths>
#include <QPainter>
#include <QCloseEvent>
#include <QEvent>
#include <QFileInfoList>
#include <QMenu>
#include <QMessageBox>
#include <QDebug>
#include <QMovie>

#include "mainwindow.h"
#include "ui_mainwindow.h"

extern "C"
{
#include "libavformat/avformat.h"
}

#define VOLUME_INT  (13)


MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    m_MainDecoder(new MainDecoder),
    m_menuTimer(new QTimer),
    m_progressTimer(new QTimer),
    menuIsVisible(true),
    isKeepAspectRatio(false),
    m_video_image(QImage(":/image/MUSIC.jpg")),
    //    loopPlay(false),
    closeNotExit(false),
    playState(MainDecoder::STOP),
    seekInterval(15),
    m_bDrag(false)
{
    ui->setupUi(this);

    qRegisterMetaType<MainDecoder::PlayState>("MainDecoder::PlayState");

    m_menuTimer->start(3000);  //每隔3秒，检测状态，自动隐藏
    m_progressTimer->setInterval(500); //更新播放的时间进度

    initUI();
    initSlot();
    initFFmpeg();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initUI()
{
    this->setWindowTitle("QtFFmpegPlayer");
    this->setWindowIcon(QIcon(":/image/player.ico"));

    //开启鼠标移动事件的捕获。
    this->setMouseTracking(true);

    ui->titleLable->setAlignment(Qt::AlignCenter);

    ui->labelTime->setStyleSheet("background-color:#000;font-size:20px;font-weight:bold;color:#fff;");
    ui->labelTime->setText(QString("00.00.00 / 00:00:00"));

    ui->btnStop->setIcon(QIcon(":/image/stop.ico"));
//    ui->btnStop->setIconSize(QSize(48, 48));
//    ui->btnStop->setStyleSheet("background: transparent;border:none;");

    ui->btnPause->setIcon(QIcon(":/image/play.ico"));
//    ui->btnPause->setIconSize(QSize(48, 48));
//    ui->btnPause->setStyleSheet("background: transparent;border:none;");

    setHide(ui->frame1);
    setHide(ui->frame2);
    setHide(ui->frame3);
    setHide(ui->frame4);
}

void MainWindow::initFFmpeg()
{
//    av_log_set_level(AV_LOG_INFO);

    avfilter_register_all();

    /* ffmpeg init */
    av_register_all();

    /* ffmpeg network init for rtsp */
    if (avformat_network_init()) {
        qDebug() << "avformat network init failed";
    }

    /* init sdl audio */
    if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
        qDebug() << "SDL init failed";
    }
}

void MainWindow::initSlot()
{
    connect(ui->btnOpenLocal,   SIGNAL(clicked(bool)), this, SLOT(buttonClickSlot()));
    connect(ui->btnOpenUrl,     SIGNAL(clicked(bool)), this, SLOT(buttonClickSlot()));
    connect(ui->btnStop,        SIGNAL(clicked(bool)), this, SLOT(buttonClickSlot()));
    connect(ui->btnPause,       SIGNAL(clicked(bool)), this, SLOT(buttonClickSlot()));

    connect(ui->lineEdit,       SIGNAL(cursorPositionChanged(int,int)),     this, SLOT(editText()));

    connect(m_menuTimer,      SIGNAL(timeout()), this, SLOT(timerSlot()));
    connect(m_progressTimer,  SIGNAL(timeout()), this, SLOT(timerSlot()));

    connect(ui->videoProgressSlider,    SIGNAL(sliderMoved(int)), this, SLOT(seekProgress(int)));

    connect(this, SIGNAL(selectedVideoFile(QString,QString)),   m_MainDecoder, SLOT(decoderFile(QString,QString)));
    connect(this, SIGNAL(stopVideo()),                          m_MainDecoder, SLOT(stopVideo()));
    connect(this, SIGNAL(pauseVideo()),                         m_MainDecoder, SLOT(pauseVideo()));

    connect(m_MainDecoder, SIGNAL(playStateChanged(MainDecoder::PlayState)),  this, SLOT(playStateChanged(MainDecoder::PlayState)));
    connect(m_MainDecoder, SIGNAL(gotVideoTime(qint64)),                  this, SLOT(videoTime(qint64)));
    connect(m_MainDecoder, SIGNAL(gotVideo(QImage)),                      this, SLOT(showVideo(QImage)));
}

///////////////////////////////////////
void MainWindow::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);

    painter.setRenderHint(QPainter::Antialiasing, true);

    int width = this->width();
    int height = this->height();


    painter.setBrush(Qt::black);
    painter.drawRect(0, 0, width, height);

    //是否保持宽高比
    if (isKeepAspectRatio) {
        QImage img = m_video_image.scaled(QSize(width, height), Qt::KeepAspectRatio);

        /* calculate display position */
        int x = (this->width() - img.width()) / 2;
        int y = (this->height() - img.height()) / 2;

        painter.drawImage(QPoint(x, y), img);
    } else {
        QImage img = m_video_image.scaled(QSize(width, height));

        painter.drawImage(QPoint(0, 0), img);
    }
}

void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
    int progressVal;
    int volumnVal = m_MainDecoder->getVolume();

    switch (event->key()) {
    case Qt::Key_Up:
        if (volumnVal + VOLUME_INT > SDL_MIX_MAXVOLUME) {
            m_MainDecoder->setVolume(SDL_MIX_MAXVOLUME);
        } else {
            m_MainDecoder->setVolume(volumnVal + VOLUME_INT);
        }
        break;

    case Qt::Key_Down:
        if (volumnVal - VOLUME_INT < 0) {
            m_MainDecoder->setVolume(0);
        } else {
            m_MainDecoder->setVolume(volumnVal - VOLUME_INT);
        }
        break;

    case Qt::Key_Left:
        if (ui->videoProgressSlider->value() > seekInterval) {
            progressVal = ui->videoProgressSlider->value() - seekInterval;
            m_MainDecoder->seekProgress(static_cast<qint64>(progressVal) * 1000000);
        }
        break;

    case Qt::Key_Right:
        if (ui->videoProgressSlider->value() + seekInterval < ui->videoProgressSlider->maximum()) {
            progressVal = ui->videoProgressSlider->value() + seekInterval;
            m_MainDecoder->seekProgress(static_cast<qint64>(progressVal) * 1000000);
        }
        break;

    case Qt::Key_Escape:
        showNormal();
        break;

    case Qt::Key_Space:
        emit pauseVideo();
        break;

    default:

        break;
    }
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    Q_UNUSED(event);

    /* stop timer & restart it while having mouse moving */
    if (currentPlayType == "video") {
        m_menuTimer->stop();
        if (!menuIsVisible) {
            showControls(true);
            menuIsVisible = true;
            QApplication::setOverrideCursor(Qt::ArrowCursor);
        }
        m_menuTimer->start();
    }

    if(m_bDrag)
    {
        //获得鼠标移动的距离
        QPoint distance = event->globalPos() - m_mouseStartPoint;
        //QPoint distance = event->pos() - mouseStartPoint;
        //改变窗口的位置
        this->move(m_windowTopLeftPoint + distance);
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        m_bDrag = true;
        //获得鼠标的初始位置
        m_mouseStartPoint = event->globalPos();
        //mouseStartPoint = event->pos();
        //获得窗口的初始位置
        m_windowTopLeftPoint = this->frameGeometry().topLeft();
    }
}

void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        m_bDrag = false;
    }
}

void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
    if (event->buttons() == Qt::LeftButton) {
        if (isFullScreen()) {
            showNormal();
        } else {
            showFullScreen();
        }
    }
}

/////////////////////////////////////

void MainWindow::setHide(QWidget *widget)
{
    m_hideVector.push_back(widget);
}

void MainWindow::showControls(bool show)
{
    if (show) {
        for (QWidget *widget : m_hideVector) {
            widget->show();
        }
    } else {
        for (QWidget *widget : m_hideVector) {
            widget->hide();
        }
    }
}

inline QString MainWindow::getFilenameFromPath(QString path)
{
    return path.right(path.size() - path.lastIndexOf("/") - 1);
}

QString MainWindow::fileType(QString file)
{
    QString type;

    QString suffix = file.right(file.size() - file.lastIndexOf(".") - 1);
    if (suffix == "mp3" || suffix == "aac" || suffix == "ape" || suffix == "flac" || suffix == "wav") {
        type = "music";
    } else {
        type = "video";
    }

    return type;
}

void MainWindow::addPathVideoToList(QString path)
{
    QDir dir(path);

    QRegExp rx(".*\\.(264|rmvb|flv|mp4|mov|avi|mkv|ts|wav|flac|ape|mp3)$");

    QFileInfoList list = dir.entryInfoList(QDir::Files);
    for(int i = 0; i < list.count(); i++) {
        QFileInfo fileInfo = list.at(i);

        if (rx.exactMatch(fileInfo.fileName())) {
            QString filename = getFilenameFromPath(fileInfo.fileName());
            /* avoid adding repeat file */
            if (!playList.contains(filename)) {
                playList.push_back(fileInfo.absoluteFilePath());
            }
        }
    }
}

void MainWindow::playVideo(QString file)
{
    emit stopVideo();

    currentPlay = file;
    currentPlayType = fileType(file);
    if (currentPlayType == "video") {
        m_menuTimer->start();
        ui->titleLable->setText("");
    } else {
        m_menuTimer->stop();
        if (!menuIsVisible) {
            showControls(true);
            menuIsVisible = true;
        }
        ui->titleLable->setStyleSheet("color:rgb(25, 125, 203);font-size:24px;background: transparent;");
        ui->titleLable->setText(QString("当前播放：%1").arg(getFilenameFromPath(file)));
    }

    emit selectedVideoFile(file, currentPlayType);
}

/******************* slot ************************/

void MainWindow::buttonClickSlot()
{
    QString filePath;

    if (QObject::sender() == ui->btnOpenLocal) { // open local file
        filePath = QFileDialog::getOpenFileName(
                this, "选择播放文件", "/",
                "(*.264 *.mp4 *.rmvb *.avi *.mov *.flv *.mkv *.ts *.mp3 *.flac *.ape *.wav)");
        if (!filePath.isNull() && !filePath.isEmpty()) {
            playVideo(filePath);

            QString path = filePath.left(filePath.lastIndexOf("/") + 1);
            addPathVideoToList(path);
        }
    } else if (QObject::sender() == ui->btnOpenUrl) {   // open network file
        filePath = ui->lineEdit->text();
        if (!filePath.isNull() && !filePath.isEmpty()) {
            QString type = "video";
            emit selectedVideoFile(filePath, type);
        }
    } else if (QObject::sender() == ui->btnStop) {
        emit stopVideo();
    } else if (QObject::sender() == ui->btnPause) {
        emit pauseVideo();
    }
}

void MainWindow::timerSlot()
{
    if (QObject::sender() == m_menuTimer) {
        if (menuIsVisible && playState == MainDecoder::PLAYING) {
            if (isFullScreen()) {
                QApplication::setOverrideCursor(Qt::BlankCursor);
            }
            showControls(false);
            menuIsVisible = false;
        }
    } else if (QObject::sender() == m_progressTimer) {
        if (menuIsVisible && playState == MainDecoder::PAUSE){
            return;
        }
        qint64 currentTime = static_cast<qint64>(m_MainDecoder->getCurrentTime());
        ui->videoProgressSlider->setValue( static_cast<int>(currentTime) );
        ///qDebug() << "currentTime::" << currentTime;
        int hourCurrent = currentTime / 60 / 60;
        int minCurrent  = (currentTime / 60) % 60;
        int secCurrent  = currentTime % 60;

        int hourTotal = timeTotal / 60 / 60;
        int minTotal  = (timeTotal / 60) % 60;
        int secTotal  = timeTotal % 60;

        ui->labelTime->setText(QString("%1.%2.%3 / %4:%5:%6")
                               .arg(hourCurrent, 2, 10, QLatin1Char('0'))
                               .arg(minCurrent, 2, 10, QLatin1Char('0'))
                               .arg(secCurrent, 2, 10, QLatin1Char('0'))
                               .arg(hourTotal, 2, 10, QLatin1Char('0'))
                               .arg(minTotal, 2, 10, QLatin1Char('0'))
                               .arg(secTotal, 2, 10, QLatin1Char('0')));
    }
}

void MainWindow::seekProgress(int value)
{
    m_MainDecoder->seekProgress(static_cast<qint64>(value) * 1000000);
}

void MainWindow::editText()
{
    /* forbid control hide while inputting */
    m_menuTimer->stop();
    m_menuTimer->start();
}

void MainWindow::videoTime(qint64 time)
{
    timeTotal = time / 1000000;

    ui->videoProgressSlider->setRange(0, timeTotal);

    int hour = timeTotal / 60 / 60;
    int min  = (timeTotal / 60 ) % 60;
    int sec  = timeTotal % 60;

    ui->labelTime->setText(QString("00.00.00 / %1:%2:%3")
                           .arg(hour, 2, 10, QLatin1Char('0'))
                           .arg(min,  2, 10, QLatin1Char('0'))
                           .arg(sec,  2, 10, QLatin1Char('0')));
}

void MainWindow::showVideo(QImage image)
{
    this->m_video_image = image;
    update();
}

void MainWindow::playStateChanged(MainDecoder::PlayState state)
{
    switch (state) {
    case MainDecoder::PLAYING:
        ui->btnPause->setIcon(QIcon(":/image/pause.ico"));
        playState = MainDecoder::PLAYING;
        m_progressTimer->start();
        break;

    case MainDecoder::STOP:
        m_video_image = QImage(":/image/MUSIC.jpg");
        ui->btnPause->setIcon(QIcon(":/image/play.ico"));
        playState = MainDecoder::STOP;
        m_progressTimer->stop();
        ui->labelTime->setText(QString("00.00.00 / 00:00:00"));
        ui->videoProgressSlider->setValue(0);
        timeTotal = 0;
        update();
        break;

    case MainDecoder::PAUSE:
        ui->btnPause->setIcon(QIcon(":/image/play.ico"));
        playState = MainDecoder::PAUSE;
        break;

    case MainDecoder::FINISH:
        qDebug() << "...MainDecoder::FINISH...";
        emit stopVideo();

        if (loopPlay) {  //循环播放，代码里没有设置这个变量的地方，暂不使用。
            emit selectedVideoFile(currentPlay, currentPlayType);
        }else {
            m_video_image = QImage(":/image/MUSIC.jpg");
            playState = MainDecoder::STOP;

            m_progressTimer->stop();
            ui->labelTime->setText(QString("00.00.00 / 00:00:00"));
            ui->videoProgressSlider->setValue(0);
            timeTotal = 0;
        }

        break;

    default:

        break;
    }
}
